package me.flyray.gate.filter;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import me.flyray.gate.feign.ILogService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import me.flyray.auth.client.jwt.UserAuthUtil;
import me.flyray.auth.common.config.UserAuthConfig;
import me.flyray.auth.common.util.jwt.IJWTInfo;
import me.flyray.common.context.BaseContextHandler;
import me.flyray.common.msg.ResponseCode;
import me.flyray.gate.utils.FilterUrlUtils;
import me.flyray.gate.utils.RequestExceptionUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

/**
 * @Author: bolei
 * @date: 17:47 2018/11/24
 * @Description: token拦截器 统一的鉴权，权限过滤
 */
@Component
@Slf4j
public class JwtTokenFilter extends ZuulFilter {
	@Autowired
    private RedisTemplate<String, String> redisTemplate;
	@Autowired
	private UserAuthConfig userAuthConfig;
	@Autowired
	private UserAuthUtil userAuthUtil;
	@Autowired
	private FilterUrlUtils filterUrlUtils;
	@Autowired
	@Lazy
	private ILogService logService;
    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 2;
    }

    @Override
    public boolean shouldFilter() {
        return !filterUrlUtils.filterIgnoreUrl(0);
    }

    @Override
    public Object run() {
    	RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();

		//接口有两种类型:一种是管理后台的接口需要验证登陆之后的token，一种是给app、小程序、h5的接口、需要验证appId（平台id） sign key
		//有用户体系的需要验证用户的token
		IJWTInfo user = null;
		String authToken = request.getHeader(userAuthConfig.getTokenHeader());
		if (StringUtils.isEmpty(authToken)){
			RequestExceptionUtils.setFailedRequest(ResponseCode.TOKEN_ISNULL_CODE.getCode(),ResponseCode.TOKEN_ISNULL_CODE.getMessage());
		}
		try {
			user = getJWTUser(request, ctx);
			if(null==user){
				log.info("获取授权token报错：获取的token是null");
				RequestExceptionUtils.setFailedRequest(ResponseCode.TOKEN_ISNULL_CODE.getCode(),ResponseCode.TOKEN_ISNULL_CODE.getMessage());
				return null;
			}
			//将用户信息放回request中
			//setRequestParam(request, ctx, user);
		} catch (Exception e) {
			log.info("获取授权token无效报错："+e.getMessage());
			RequestExceptionUtils.setFailedRequest(ResponseCode.TOKEN_ISNOTVALID_CODE.getCode(),ResponseCode.TOKEN_ISNOTVALID_CODE.getMessage());
			return null;
		}
		//对外提供服务所用的token
		if(filterUrlUtils.filterIgnoreUrl(0)){
			boolean istokenvalid=false;
			/**
        	 * 验证token
        	 * */
        	try {
				istokenvalid=checkToken(user.getPlatformId(),request);
				if(!istokenvalid){//验证token失败 TOKEN_CHECKFAIL_CODE
					log.info("验证比对Token数据不一致: redis缓存平台编号---"+user.getPlatformId());
					RequestExceptionUtils.setFailedRequest(ResponseCode.TOKEN_CHECKFAIL_CODE.getCode(),ResponseCode.TOKEN_CHECKFAIL_CODE.getMessage());
					return null;
	        	}
			} catch (Exception e) {
				log.info("验证Token数据报错:"+e.getMessage());
				RequestExceptionUtils.setFailedRequest(ResponseCode.TOKEN_CHECKFAIL_CODE.getCode(),ResponseCode.TOKEN_CHECKFAIL_CODE.getMessage());
		         return null;
			}
		}
		return null;
    }
    
    /**
	 * 返回session中的用户信息
	 *
	 * @param request
	 * @param ctx
	 * @return
	 */
	private IJWTInfo getJWTUser(HttpServletRequest request, RequestContext ctx) throws Exception {
		String authToken = request.getHeader(userAuthConfig.getTokenHeader());
		/*if (StringUtils.isEmpty(authToken)) {
			authToken = request.getParameter("token");
		}*/
		ctx.addZuulRequestHeader(userAuthConfig.getTokenHeader(), authToken);
		BaseContextHandler.setToken(authToken);
		return userAuthUtil.getInfoFromToken(authToken);
	}
	/**
	 * 验证当前应用的token是否正确:应用传参过来的token和缓存中的token比对
	 * @author
	 * */
	private boolean checkToken(String platformId,HttpServletRequest request)throws Exception{
		String authToken = request.getHeader(userAuthConfig.getTokenHeader());
		String cacheAuthToken=String.valueOf(redisTemplate.opsForValue().get("auth:token_"+platformId));
		if("".equals(cacheAuthToken)||null==cacheAuthToken){
			return false;
		}
		if(authToken.equals(cacheAuthToken)){
			return true;
		}
		return false;
	}

	private void setRequestParam(HttpServletRequest request,RequestContext ctx, IJWTInfo user){
		// 例如在请求参数中添加 userId
		try {
			InputStream in = ctx.getRequest().getInputStream();
			String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
			if(StringUtils.isBlank(body)){
				body = "{}";
			}
			JSONObject jsonObject = JSON.parseObject(body);
			jsonObject.put("user", user);
			String newBody = jsonObject.toString();
			final byte[] reqBodyBytes = newBody.getBytes();
			ctx.setRequest(new HttpServletRequestWrapper(request){
				@Override
				public ServletInputStream getInputStream() throws IOException {
					return new ServletInputStreamWrapper(reqBodyBytes);
				}
				@Override
				public int getContentLength() {
					return reqBodyBytes.length;
				}
				@Override
				public long getContentLengthLong() {
					return reqBodyBytes.length;
				}
			});
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}
